//
//  MyMapGrab.m
//  iPhoneKML
//
//  Created by Benjamin Blundell on 28/10/2009.
//  Copyright 2009 Section9. All rights reserved.
//

#import "MyMapGrab.h"


@implementation MyMapGrab

@synthesize username;
@synthesize password;
@synthesize delegate;
@synthesize mMapFeed;
@synthesize mMapDetailsFeed;
@synthesize mMapFeedTicket;
@synthesize mMapFetchError;
@synthesize mEntireMapFeed;

// TODO: On errors, refresh all views and clean all data + return to base
// view. This means an extra delegate method

#pragma mark -
#pragma mark Init Methods

-(id) initWithUsername:(NSString*) user andPassword:(NSString*) pass{
	
	self = [super init];
	if (self != nil) {
		self.username = [user retain];
		self.password = [pass retain];
		lastMapGrabbed = -1;
	}
	return self;
}


#pragma mark -
#pragma mark Google Service

// get a map service object with the current username/password
//
// A "service" object handles networking tasks.  Service objects
// contain user authentication information as well as networking
// state information (such as cookies and the "last modified" date for
// fetched data.)

- (GDataServiceGoogleMaps *)mapService {
	
	static GDataServiceGoogleMaps* service = nil;
	
	if (!service) {
		service = [[GDataServiceGoogleMaps alloc] init];
		
		// iPhone apps typically would not turn on the caching here
		// to avoid the memory usage
		[service setShouldCacheDatedData:NO];
		[service setServiceShouldFollowNextLinks:YES];
		
		// iPhone apps will typically disable caching dated data or will call
		// clearLastModifiedDates after done fetching to avoid wasting
		// memory.    
	}
	
		
	[service setUserAgent:@"Section9-SampleMapsApp-1.0"]; // set this to yourName-appName-appVersion
	[service setUserCredentialsWithUsername:self.username
								   password:self.password];
	
	NSLog(@"Username %@ and Password %@",self.username,self.password);
	
	return service;
}

#pragma mark -
#pragma mark Fetch All Feeds


// Fetch the entire feed. Use this to create presentable, persistant data on the iPhone all at once

- (void) fetchEntireFeed {
	self.mMapFeed = nil;
	self.mMapFetchError = nil;
	self.mEntireMapFeed = nil;
	
	self.mEntireMapFeed = [[NSMutableDictionary alloc] init];
	
	GDataServiceGoogleMaps *service = [self mapService];
	NSURL *feedURL = [GDataServiceGoogleMaps mapsFeedURLForUserID:kGDataServiceDefaultUser
													   projection:kGDataMapsProjectionFull];
	
	GDataServiceTicket *ticket;
	ticket = [service fetchFeedWithURL:feedURL
							  delegate:self
					 didFinishSelector:@selector(mapsTicket:finishedEntireFeed:error:)];
	
	[ticket setIsRetryEnabled:FALSE];
	
	self.mMapFeedTicket = ticket;
}


// map feed fetch callback
- (void)mapsTicket:(GDataServiceTicket *)ticket
  finishedEntireFeed:(GDataFeedMap *)feed
             error:(NSError *)error {
	
	[[self mapService] clearLastModifiedDates];
	
	if (error){
		
#ifdef DEBUG
		NSLog(@"Map Grab Error: %@", [error localizedDescription]);
#endif
		
		UIAlertView *someError = [[UIAlertView alloc] initWithTitle: @"MyMap Error" message: @"Could not connect to Google. Please Check your username and password" delegate: self cancelButtonTitle: @"Ok" otherButtonTitles: nil];
		
		[someError show];
		[someError release];
		if (self.delegate)
			[self.delegate myMapGrabDelegate:self didReceiveError:error];
		
		self.mMapFeed = nil;
		self.mMapFetchError = nil;
		return;
	}
	
	numMapsToGrab = [[feed entries] count];
	self.mMapFeed = feed;
	[feed retain];
	
	if (feed){		
		
		for (id entry in [feed entries]){
			
			self.mMapFetchError = nil;
			GDataServiceGoogleMaps *service = [self mapService];
			// fetch the feed of features
			NSURL *featuresFeedURL = [entry featuresFeedURL];
			if (featuresFeedURL) {
				
				GDataServiceTicket *ticket;
				ticket = [service fetchFeedWithURL:featuresFeedURL
										  delegate:self
								 didFinishSelector:@selector(featuresTicket:finishedWithMap:error:)];
				
				[ticket setUserData:entry];
			//	[ticket setProperty:entry withKey:@"currentMap"];
				
				self.mMapFeedTicket = ticket;
			}
		}
	}
}

	

// features fetch callback
- (void)featuresTicket:(GDataServiceTicket *)ticket
      finishedWithMap:(GDataFeedMapFeature *)feed
                 error:(NSError *)error {
	
	GDataEntryMap *currentMap = [ticket userData];
	numMapsToGrab--;
	if (error){
		
#ifdef DEBUG
		NSLog(@"Map Grab Error: %@", [error localizedDescription]);
#endif
		
		UIAlertView *someError = [[UIAlertView alloc] initWithTitle: @"MyMap Error" 
													message: [NSString stringWithFormat:@"Could not grab map -%@. Please ensure you own this map ",[[currentMap title] stringValue]]
														   delegate: self cancelButtonTitle: @"Ok" otherButtonTitles: nil];
		
		[someError show];
		[someError release];
		if (self.delegate)
			[self.delegate myMapGrabDelegate:self didReceiveError:error];
		
		self.mMapDetailsFeed = nil;
		
		return;
	}
	
	
	
	if (feed){
		self.mMapDetailsFeed = feed;
		
		NSMutableDictionary* myfeatures = [[NSMutableDictionary alloc] init];
		for (id entry in [feed entries]){
			
			// Cheap and nasty RegExp lookup - Works though
			
			NSArray *kml = [entry KMLValues];
			GDataXMLElement *test = [kml objectAtIndex:0];
			NSString *searchString = [test XMLString]; 
		//	NSString *regexString = @"\<coordinates\>(.*),0.0\<\/coordinates\>";
			NSString *regexString = @"<coordinates>(.*),0.0</coordinates>"; 
			NSString *matchedString = [searchString stringByMatching:regexString capture:1L];
			//[matchedString retain];
			
#ifdef DEBUG
			NSLog(@"Details Entry: %@",[[entry title] stringValue] );
			NSLog(@"Details Entry: %@", [test XMLString]);
			NSLog(@"matchedString: '%@'", matchedString); 
#endif		
			
			// Idea here is to create a master dictionary we can save and return to our main class
			// Dictionary looks like this: Dict(MapName -> Dict(Placename,GPS))
			
			[myfeatures setObject:matchedString forKey:[[entry title] stringValue] ]; // Possibly overkill here but hey?
		}
		
		#ifdef DEBUG
		NSLog(@"Setting Current Map Data For: '%@'", [[currentMap title] stringValue]); 
		#endif
		[self.mEntireMapFeed setObject:myfeatures forKey:[[currentMap title] stringValue]];
	}
	
	if (numMapsToGrab == 0 && self.delegate){
	
		[delegate myMapGrabDelegate:self fetchedAllData:self.mEntireMapFeed];
	}
}





#pragma mark -
#pragma mark Fetch Individual Feeds


// begin retrieving the list of the user's maps
- (void)fetchFeedOfMaps {
	
	self.mMapFeed = nil;
	self.mMapFetchError = nil;

	
	GDataServiceGoogleMaps *service = [self mapService];
	NSURL *feedURL = [GDataServiceGoogleMaps mapsFeedURLForUserID:kGDataServiceDefaultUser
													   projection:kGDataMapsProjectionFull];
			
	GDataServiceTicket *ticket;
	ticket = [service fetchFeedWithURL:feedURL
							  delegate:self
					 didFinishSelector:@selector(mapsTicket:finishedWithFeed:error:)];
	
	self.mMapFeedTicket = ticket;
	
}



// map feed fetch callback
- (void)mapsTicket:(GDataServiceTicket *)ticket
  finishedWithFeed:(GDataFeedMap *)feed
             error:(NSError *)error {
	
	if (error){
		
		UIAlertView *someError = [[UIAlertView alloc] initWithTitle: @"MyMap Error" message: @"Could not connect to Google. Please Check your username and password" delegate: self cancelButtonTitle: @"Ok" otherButtonTitles: nil];
		
		[someError show];
		[someError release];
		if (self.delegate)
			[self.delegate myMapGrabDelegate:self didReceiveError:error];
		
		self.mMapFeed = nil;
		self.mMapFetchError = nil;
		return;
	}
	
	
	self.mMapFeed = feed;
	[feed retain];
	
	if (feed && self.delegate){
		NSMutableDictionary* mymaps = [[NSMutableDictionary alloc] init];
		for (id entry in [feed entries]){
			[mymaps setObject:entry forKey:[[entry title] stringValue]]; // Possibly overkill here but hey?
		}
	
		[delegate myMapGrabDelegate:self finishedMapFetch:mymaps];
	}
	
	
}

// for the map selected in the top list, begin retrieving the lists of
// features and tables
- (void)fetchFeedOfPlacesWithMap:(NSInteger)mapindex {
	
	if (self.mMapFeed && (lastMapGrabbed != mapindex || self.mMapDetailsFeed == nil)){
		
		GDataEntryMap *map;
		NSArray *maps = [self.mMapFeed entries];
				
		if ([maps count] > 0 && mapindex > -1) {
			map = [maps objectAtIndex:mapindex];
		}
		
		if (map) {
			self.mMapFetchError = nil;
			GDataServiceGoogleMaps *service = [self mapService];
			// fetch the feed of features
			NSURL *featuresFeedURL = [map featuresFeedURL];
			if (featuresFeedURL) {
				
				GDataServiceTicket *ticket;
				ticket = [service fetchFeedWithURL:featuresFeedURL
										delegate:self
								didFinishSelector:@selector(featuresTicket:finishedWithFeed:error:)];
				
				self.mMapFeedTicket = ticket;
			}
			lastMapGrabbed = mapindex;
		}
	}
	else if (self.mMapDetailsFeed){
		// Call with existing data. Saves re-requests
		[self featuresTicket:self.mMapFeedTicket finishedWithFeed:self.mMapDetailsFeed error:nil];
	}
}

// features fetch callback
- (void)featuresTicket:(GDataServiceTicket *)ticket
      finishedWithFeed:(GDataFeedMapFeature *)feed
                 error:(NSError *)error {
	
	if (error){
		
		
		UIAlertView *someError = [[UIAlertView alloc] initWithTitle: @"MyMap Error" message: [error localizedDescription]
														   delegate: self cancelButtonTitle: @"Ok" otherButtonTitles: nil];
		
		[someError show];
		[someError release];
		if (self.delegate)
			[self.delegate myMapGrabDelegate:self didReceiveError:error];

		self.mMapDetailsFeed = nil;
		
		return;
	}
	
	
	
	if (feed && self.delegate){
		self.mMapDetailsFeed = feed;
		
		NSMutableDictionary* myfeatures = [[NSMutableDictionary alloc] init];
		for (id entry in [feed entries]){
			
			// Cheap and nasty RegExp lookup - Works though
			
			NSArray *kml = [entry KMLValues];
			GDataXMLElement *test = [kml objectAtIndex:0];
			NSString *searchString = [test XMLString]; 
			//NSString *regexString = @"\<coordinates\>(.*),0.0\<\/coordinates\>";
			NSString *regexString = @"<coordinates>(.*),0.0</coordinates>"; 
			NSString *matchedString = [searchString stringByMatching:regexString capture:1L];
			//[matchedString retain];
			
#ifdef DEBUG
			NSLog(@"Details Entry: %@",[[entry title] stringValue] );
			NSLog(@"Details Entry: %@", [test XMLString]);
			NSLog(@"matchedString: '%@'", matchedString); 
#endif		
			[myfeatures setObject:matchedString forKey:[[entry title] stringValue] ]; // Possibly overkill here but hey?
		}
		
		[self.delegate myMapGrabDelegate:self finishedMapDetailsFetch:myfeatures];
	}
	
}



#pragma mark -
#pragma mark Memory Management Cleanup

- (void) dealloc {
	[super dealloc];
	[self.mMapFeed		release];
	[self.mMapFeedTicket release];
	[self.mMapFetchError release];

}


@end
